package com.example.service.impl;

import com.example.domain.valueobject.Money;
import com.example.domain.valueobject.Quantity;
import com.example.exception.ErrorCode;
import com.example.exception.InvalidRequestException;
import com.example.service.PricingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 价格计算服务实现类
 * 
 * @author Means
 * @since 2025-10-27
 */
@Slf4j
@Service
public class PricingServiceImpl implements PricingService {
    
    // ==================== 价格计算 ====================
    
    @Override
    public Money calculateLineAmount(Quantity quantity, Money unitPrice) {
        log.debug("计算行金额: quantity={}, unitPrice={}", quantity, unitPrice);
        
        if (quantity == null || unitPrice == null) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, "数量和单价不能为空");
        }
        
        // 数量 × 单价
        return unitPrice.multiply(quantity.getValue());
    }
    
    @Override
    public Money calculateLineAmount(BigDecimal quantity, BigDecimal unitPrice) {
        log.debug("计算行金额: quantity={}, unitPrice={}", quantity, unitPrice);
        
        if (quantity == null || unitPrice == null) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, "数量和单价不能为空");
        }
        
        if (quantity.compareTo(BigDecimal.ZERO) < 0 || unitPrice.compareTo(BigDecimal.ZERO) < 0) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, "数量和单价不能为负数");
        }
        
        return Money.of(quantity.multiply(unitPrice));
    }
    
    // ==================== 折扣计算 ====================
    
    @Override
    public Money applyDiscountRate(Money originalAmount, BigDecimal discountRate) {
        log.debug("应用折扣率: originalAmount={}, discountRate={}", originalAmount, discountRate);
        
        if (originalAmount == null || discountRate == null) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, "原金额和折扣率不能为空");
        }
        
        if (!isValidDiscountRate(discountRate)) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, 
                    "折扣率必须在0到1之间: " + discountRate);
        }
        
        // 原价 × 折扣率
        return originalAmount.multiply(discountRate);
    }
    
    @Override
    public Money applyFixedDiscount(Money originalAmount, Money discountAmount) {
        log.debug("应用固定折扣: originalAmount={}, discountAmount={}", originalAmount, discountAmount);
        
        if (originalAmount == null || discountAmount == null) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, "原金额和折扣金额不能为空");
        }
        
        if (!isValidDiscountAmount(discountAmount, originalAmount)) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, 
                    "折扣金额必须大于0且小于原金额");
        }
        
        // 原价 - 折扣金额
        Money result = originalAmount.subtract(discountAmount);
        
        // 确保结果不为负数
        if (result.isNegative()) {
            return Money.zero();
        }
        
        return result;
    }
    
    // ==================== 满减计算 ====================
    
    @Override
    public Money calculateThresholdReduction(Money currentSubtotal, Money originalSubtotal,
                                            Money thresholdAmount, Money reductionAmount,
                                            boolean stackable, boolean useOriginalPrice) {
        log.debug("计算满减减免金额: current={}, original={}, threshold={}, reduction={}, stackable={}, useOriginal={}", 
                currentSubtotal, originalSubtotal, thresholdAmount, reductionAmount, stackable, useOriginalPrice);
        
        if (currentSubtotal == null || originalSubtotal == null || 
            thresholdAmount == null || reductionAmount == null) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, "金额参数不能为空");
        }
        
        // 根据配置选择判断基准
        Money judgeAmount = useOriginalPrice ? originalSubtotal : currentSubtotal;
        
        // 检查是否满足门槛
        if (!meetsThreshold(judgeAmount, thresholdAmount)) {
            log.debug("未达到满减门槛");
            return Money.zero();
        }
        
        if (stackable) {
            // 可叠加：计算总减免金额
            int count = calculateThresholdCount(judgeAmount, thresholdAmount);
            Money totalReduction = reductionAmount.multiply(count);
            log.debug("可叠加满减: 次数={}, 总减免={}", count, totalReduction);
            return totalReduction;
        } else {
            // 不可叠加：返回单次减免
            log.debug("单次满减: 减免={}", reductionAmount);
            return reductionAmount;
        }
    }
    
    @Override
    public int calculateThresholdCount(Money totalAmount, Money thresholdAmount) {
        if (totalAmount == null || thresholdAmount == null) {
            return 0;
        }
        
        if (!meetsThreshold(totalAmount, thresholdAmount)) {
            return 0;
        }
        
        // 总金额 ÷ 门槛金额（向下取整）
        BigDecimal count = totalAmount.getCalculationAmount()
                .divide(thresholdAmount.getCalculationAmount(), 0, RoundingMode.DOWN);
        
        return count.intValue();
    }
    
    // ==================== 总价计算 ====================
    
    @Override
    public Money calculateSubtotal(List<Money> lineAmounts) {
        log.debug("计算小计: lineCount={}", lineAmounts != null ? lineAmounts.size() : 0);
        
        if (lineAmounts == null || lineAmounts.isEmpty()) {
            return Money.zero();
        }
        
        Money subtotal = Money.zero();
        for (Money amount : lineAmounts) {
            if (amount != null) {
                subtotal = subtotal.add(amount);
            }
        }
        
        log.debug("小计金额: {}", subtotal);
        return subtotal;
    }
    
    @Override
    public Money calculatePayableAmount(Money subtotal, Money discountTotal) {
        log.debug("计算应付金额: subtotal={}, discountTotal={}", subtotal, discountTotal);
        
        if (subtotal == null) {
            throw new InvalidRequestException(ErrorCode.PARAMETER_ERROR, "小计金额不能为空");
        }
        
        if (discountTotal == null || discountTotal.isZero()) {
            return subtotal;
        }
        
        Money payable = subtotal.subtract(discountTotal);
        
        // 确保结果不为负数
        if (payable.isNegative()) {
            return Money.zero();
        }
        
        return payable;
    }
    
    // ==================== 促销规则验证 ====================
    
    @Override
    public boolean meetsThreshold(Money amount, Money threshold) {
        if (amount == null || threshold == null) {
            return false;
        }
        
        return amount.greaterThanOrEqual(threshold);
    }
    
    @Override
    public boolean isValidDiscountRate(BigDecimal discountRate) {
        if (discountRate == null) {
            return false;
        }
        
        // 折扣率必须在 (0, 1) 范围内，严格小于1
        return discountRate.compareTo(BigDecimal.ZERO) > 0 
                && discountRate.compareTo(BigDecimal.ONE) < 0;
    }
    
    @Override
    public boolean isValidDiscountAmount(Money discountAmount, Money originalAmount) {
        if (discountAmount == null || originalAmount == null) {
            return false;
        }
        
        // 折扣金额必须大于0且小于原金额
        return discountAmount.isPositive() && discountAmount.lessThan(originalAmount);
    }
}

